/*
 * @Date: 2020-08-13 14:10:51
 * @Description:
 * @FilePath: \web-whole-process-hunan\src\plugin\axios\index.js
 */
// import Vue from 'vue'
import router from '@/router'
import axios from 'axios'
import store from '@/store'
import Cookies from 'js-cookie'
import { v4 as uuidv4 } from 'uuid'


import { rsa, AESEncode, AESDecode, sha256, decryptPublic } from '@/plugin/utils/encode'

axios.defaults.headers.post['Content-Type'] = 'application/json'

const isDev = process.env.NODE_ENV === 'development'
// 创建一个 axios 实例
const service = axios.create({
  timeout: 60000
  // headers: {
  //   'userId': store.getters.userId ? store.getters.userId : ''
  // }
})
const CancelToken = axios.CancelToken
const pending = []
// 请求开始和完成后清除缓冲池
const cancelPending = ({ url, method }) => {
  pending.forEach(({ u, c }, i) => {
    // 当缓存池中的请求地址和传入的一样时取消缓存池中的请求
    if (u === `${url}&${method}`) {
      c('取消重复请求')
      // 取消后删除缓存池中的记录
      pending.splice(i, 1)
    }
  })
}
// 新增缓存
const addPending = (config) => {
  const { data = {}, url, method } = config
  if (data._cancelRepeat) {
    cancelPending(config)
    config.cancelToken = new CancelToken(function executor (cancel) {
      // 缓存请求
      pending.push({ u: `${url}&${method}`, c: cancel, m: method })
    })
    delete data._cancelRepeat
  }
}
const url = ['/basics/account/encryptLogin', '/basics/account/encryptPassword']

// 取消所有的缓存池中的请求
export const cancelPendingAll = () => {
  pending.forEach(({ c }) => {
    c('取消重复请求')
  })
}
// 请求拦截器
service.interceptors.request.use(
  (config) => {
    if (window.global_config.encrypt_version === '1.0' && url.some(r => config.url.indexOf(r) > -1)) {
      config.data = paramsEncode(config)
    }

    config.headers.common['Authorization'] = $g.getToken()
    // config.headers.common['Encrypt-version'] = encrypt_version   // 暂时隐藏，全局接口加密需放开
    config.headers = Object.assign(window.global_config.header, config.headers)
    addPending(config)
    return config
  },
  (error) => {
    // 发送失败
    Promise.reject(error)
  }
)
const listContentTypeList = ['application/vnd.ms-excel;charset=utf-8', 'application/x-msdownload', 'application/vnd.ms-excel;charset=utf8', 'application/octet-stream', 'application/zip;charset=UTF-8', 'image/png;charset=UTF-8', 'image/png', 'application/pdf', 'application/vnd.ms-excel;charset=UTF-8', 'application/xls', 'application/x-msdownload;charset=UTF-8', 'application/octet-stream;charset=utf-8']

// 响应拦截器
service.interceptors.response.use(
  (response) => {
    cancelPending(response.config)

    const data = response.data
    const headers = response.headers
    // 统一对code进行强转处理
    data.status = Number(data.code || data.resCode || data.status)
    if (listContentTypeList.includes(headers['content-type'])) {
      return response
    }
    if (data.status !== 200) {
      // Message.error({ message: data.message, duration: 2000 })
      throw new Error(data.message || '返回数据有误。')
    }
    return data
  },
  (error) => {
    if (error && error.response) {
      const errorMessage = error.response.data && error.response.data.message
      console.log(error)
      switch (error.response.status) {
        case 100: error.message = '参数不能为空'; break
        case 101: error.message = '未查询到数据'; break
        case 102: error.message = '未整合所有县市下可研成果信息'; break
        case 400: error.message = '请求格式错误、参数错误'; break
        case 401: error.message = '未授权,请重新登录'; break
        case 404: error.message = '请求的资源不存在、数据不存在'; break
        case 409: error.message = '资源存在冲突、数据已存在'; break
        case 410: error.message = '重复提交'; break
        case 424: error.message = '违背数据完整性、当插入、删除和修改数据的时候，违背的数据完整性约束抛出的异常。例如：主键重复异常、存在外键关联数据依赖等'; break
        case 425: error.message = '关联关系重复'; break
        case 426: error.message = 'http解析异常'; break
        case 427: error.message = '关联文件删除异常'; break
        case 428: error.message = '关联文件不存在'; break
        case 429: error.message = '未定义流程'; break
        case 430: error.message = '文件为空，请重新上传'; break
        case 431: error.message = '存在未审核包，请审核通过后进行打包'; break
        case 432: error.message = '存在项目名称一样，请修改项目名称'; break
        case 500: error.message = errorMessage || '服务器内部错误'; break
        default: break
      }
    }
    try {
      const { status } = error.response || {}
      console.log('axios-status', status)
      if (Number(status) === 401) {
        // store.dispatch('user/logout', {
        //   vm: Vue
        // })
        localStorage.clear()
        Cookies.remove('token')
        router.replace({path: '/login'})
      }
    } catch (error) {
      console.log(error)
    }
    // Message.error({ message: error.message, duration: 2000 })
    // if (error.constructor.name !== 'Cancel') {
    //   error.message !== '取消重复请求' && Notification.error({
    //     title: '错误',
    //     message: error.message,
    //     duration: 7000
    //   })
    // }
    return Promise.reject(error)
  }
)

// rsa_公钥
const PUBLIC_KEY = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRFEUvfOMbtB6HesAYXRZLkb1snNV1eaDXv7kP5QrqSy5TbbsjjdEwCe/paLHMIIYfiNGamCfl2Xi4uqEooveGkniJj6EwVTSeSxt3qeavGsTiarQjnRYqs6VW1YZyeiK4NJQztp3ENQ4m7nqtP7s9CuGLgkQU9DGcuJfdZ9YajwIDAQAB'

// 参数加密
export const paramsEncode = (config) => {
  const params = {}
  // 登录用户名
  const token = $g.getToken()
  token && (params.authorization = token)
  // 数据加密AES密钥，客户端生成的随机字符串
  const key_str = uuidv4().toString().replace(/-/g, '')
  const dataKey = rsa(key_str, PUBLIC_KEY)
  // 请求参数aes加密
  const configData = AESEncode(JSON.stringify(config.data), key_str)

  params.data = configData

  params.dataKey = dataKey
  // 服务编码,请求地址去掉'/'
  params.serviceCode = config.url.replace(/\//g, '')
  // 时间戳
  params.time = new Date().getTime()
  // 随机数
  params.uuid = uuidv4().toString().replace(/-/g, '')
  // 请求数据签名,对params的json字符串进行SHA256算法计算摘要，然后使用公钥进行加密
  const sign = rsa(sha256(JSON.stringify(params)), PUBLIC_KEY)
  return {
    params,
    sign
  }
}

// 结果解密
export const paramsDecrypt = ({
  params,
  sign
}) => {
  // 验证与本地计算出来的sign比较
  const loaclSign = sha256(JSON.stringify(params))
  sign = decryptPublic(sign, PUBLIC_KEY)
  if (sign !== loaclSign) {
    Message.error({
      message: '数据在传输过程中被修改，请在安全的网络环境下操作',
      duration: 2000
    })
    return
  }
  // 数据加密aes秘钥, rsa进行解密
  const dataKey = decryptPublic(params.dataKey, PUBLIC_KEY)
  // 响应给客户端的数据，根据aes秘钥进行ase解密
  const data = AESDecode(params.data, dataKey)
  return JSON.parse(data)
}


const ajaxItem = {
  get: function(url, ...options){
    let list =  url.split('/')
    list.shift()
    list[0] = window.global_config.server_url[list[0]]
    url = list.join('/')
    return service.get(url, ...options)
  },
  post: function(url, ...options){
    let list =  url.split('/')
    list.shift()
    list[0] = window.global_config.server_url[list[0]]
    url = list.join('/')
    return service.post(url, ...options)
  }
}


export default ajaxItem
